// 全局函数区域
const $ = {};
$.checkfn = (obj = {})=> {
	console.log("执行了自定义公共函数checkfn");
};
// 判断数据类型
$.type = (params = {})=> {
	return Object.prototype.toString.call(params)
};
// 去重
$.unique1 = (arr = {})=> {
	return [...new Set(arr)]
};
// 去重
$.unique2 = (arr = {})=> {
	 let obj = {};
		return arr.filter(ele => {
				if (!obj[ele]) {
						obj[ele] = true;
						return true;
				}
		})
};
// 去重
$.unique3 = (arr = {})=> {
	 let result = [];
	 arr.forEach(ele => {
			 if (result.indexOf(ele) == -1) {
					 result.push(ele)
			 }
	 })
	 return result;
};
// 深拷贝(不考虑函数)
$.deepClone = (obj, result = {})=> {
	  var result = result || {};
	    for (var prop in obj) {
	        if (obj.hasOwnProperty(prop)) {
	            if (typeof obj[prop] == 'object' && obj[prop] !== null) {
	                // 引用值(obj/array)且不为null
	                if (Object.prototype.toString.call(obj[prop]) == '[object Object]') {
	                    // 对象
	                    result[prop] = {};
	                } else {
	                    // 数组
	                    result[prop] = [];
	                }
	                deepClone(obj[prop], result[prop])
	    } else {
	        // 原始值或func
	        result[prop] = obj[prop]
	    }
	  }
	}
	return result;
};
// reverse改变原数组
$.reverse = ()=> {
	var len = this.length;
	    for (var i = 0; i < len; i++) {
	        var temp = this[i];
	        this[i] = this[len - 1 - i];
	        this[len - 1 - i] = temp;
	    }
	    return this;
};
// 圣杯模式的继承
$.inherit= (Target, Origin = {})=> {
	 function F() {};
	    F.prototype = Origin.prototype;
	    Target.prototype = new F();
	    Target.prototype.constructor = Target;
	    // 最终的原型指向
	    Target.prop.uber = Origin.prototype;
};
// 找出字符串中第一次只出现一次的字母
$.firstAppear= ()=> {
	  var obj = {},
	         len = this.length;
	     for (var i = 0; i < len; i++) {
	         if (obj[this[i]]) {
	             obj[this[i]]++;
	         } else {
	             obj[this[i]] = 1;
	         }
	     }
	     for (var prop in obj) {
	        if (obj[prop] == 1) {
	          return prop;
	        }
	     }
};
// 找元素的第n级父元素
$.parents= (ele, n)=> {
	     while (ele && n) {
	          ele = ele.parentElement ? ele.parentElement : ele.parentNode;
	          n--;
	      }
	      return ele;
};
//  返回元素的第n个兄弟节点
$.retSibling= (e, n)=> {
	   while (e && n) {
	           if (n > 0) {
	               if (e.nextElementSibling) {
	                   e = e.nextElementSibling;
	               } else {
	                   for (e = e.nextSibling; e && e.nodeType !== 1; e = e.nextSibling);
	               }
	               n--;
	           } else {
	               if (e.previousElementSibling) {
	                   e = e.previousElementSibling;
	               } else {
	                   for (e = e.previousElementSibling; e && e.nodeType !== 1; e = e.previousElementSibling);
	               }
	               n++;
	           }
	       }
	       return e;
};
// 判断有没有子元素
$.hasChildren= (e)=> {
	     var children = e.childNodes,
	            len = children.length;
	        for (var i = 0; i < len; i++) {
	            if (children[i].nodeType === 1) {
	                return true;
	            }
	        }
	        return false;
};
// 一个元素插入到另一个元素的后面
$.insertAfter= (target, elen)=> {
	      var nextElen = elen.nextElenmentSibling;
	         if (nextElen == null) {
	             this.appendChild(target);
	         } else {
	             this.insertBefore(target, nextElen);
	         }
};
// 返回当前的时间（年月日时分秒）
$.getDateTime= (target, elen)=> {
					 let date = new Date(),
	         year = date.getFullYear(),
	         month = date.getMonth() + 1,
	         day = date.getDate(),
	         hour = date.getHours() + 1,
	         minute = date.getMinutes(),
	         second = date.getSeconds();
	         month = checkTime(month);
	         day = checkTime(day);
	         hour = checkTime(hour);
	         minute = checkTime(minute);
	         second = checkTime(second);
	      function checkTime(i) {
	         if (i < 10) {
	                 i = "0" + i;
	        }
	       return i;
	     }
	     return "" + year + "年" + month + "月" + day + "日" + hour + "时" + minute + "分" + second + "秒"
};
// 获得滚动条的滚动距离
$.getScrollOffset= ()=> {
	    if (window.pageXOffset) {
	            return {
	                x: window.pageXOffset,
	                y: window.pageYOffset
	            }
	        } else {
	            return {
	                x: document.body.scrollLeft + document.documentElement.scrollLeft,
	                y: document.body.scrollTop + document.documentElement.scrollTop
	            }
	        }
};
// 获得视口的尺寸
$.getViewportOffset= ()=> {
	       if (window.innerWidth) {
	            return {
	                w: window.innerWidth,
	                h: window.innerHeight
	            }
	        } else {
	            // ie8及其以下
	            if (document.compatMode === "BackCompat") {
	                // 怪异模式
	                return {
	                    w: document.body.clientWidth,
	                    h: document.body.clientHeight
	                }
	            } else {
	                // 标准模式
	                return {
	                    w: document.documentElement.clientWidth,
	                    h: document.documentElement.clientHeight
	                }
	            }
	        }
};
// 获取任一元素的任意属性
$.getStyle= (elem, prop)=> {
	   return window.getComputedStyle ? window.getComputedStyle(elem, null)[prop] : elem.currentStyle[prop]
};
// 绑定事件的兼容代码
$.addEvent= (elem, type, handle)=> {
	   if (elem.addEventListener) { //非ie和非ie9
	          elem.addEventListener(type, handle, false);
	      } else if (elem.attachEvent) { //ie6到ie8
	          elem.attachEvent('on' + type, function () {
	              handle.call(elem);
	          })
	      } else {
	          elem['on' + type] = handle;
	      }
};
// 解绑事件
$.removeEvent= (elem, type, handle)=> {
	     if (elem.removeEventListener) { //非ie和非ie9
	           elem.removeEventListener(type, handle, false);
	       } else if (elem.detachEvent) { //ie6到ie8
	           elem.detachEvent('on' + type, handle);
	       } else {
	           elem['on' + type] = null;
	       }
};
// 取消冒泡的兼容代码
$.stopBubble= (e)=> {
	    if (e && e.stopPropagation) {
	           e.stopPropagation();
	       } else {
	           window.event.cancelBubble = true;
	       }
};
// 检验字符串是否是回文
$.isPalina= (str)=> {
	    if (Object.prototype.toString.call(str) !== '[object String]') {
	           return false;
	       }
	       var len = str.length;
	       for (var i = 0; i < len / 2; i++) {
	           if (str[i] != str[len - 1 - i]) {
	               return false;
	           }
	       }
	       return true;
};
// 检验字符串是否是回文
$.isPalindrome= (str)=> {
	     str = str.replace(/\W/g, '').toLowerCase();
	     console.log(str)
	     return (str == str.split('').reverse().join(''))
};
// 兼容getElementsByClassName方法
$.getElementsByClassName= (_className)=> {
	        var allDomArray = document.getElementsByTagName('*');
	         var lastDomArray = [];
	         function trimSpace(strClass) {
	             var reg = /\s+/g;
	             return strClass.replace(reg, ' ').trim()
	         }
	         for (var i = 0; i < allDomArray.length; i++) {
	             var classArray = trimSpace(allDomArray[i].className).split(' ');
	             for (var j = 0; j < classArray.length; j++) {
	                 if (classArray[j] == _className) {
	                     lastDomArray.push(allDomArray[i]);
	                     break;
	                 }
	             }
	         }
	         return lastDomArray;
};
// 运动函数
$.animate= (obj, json, callback)=> {
	    clearInterval(obj.timer);
	       var speed,
	           current;
	       obj.timer = setInterval(function () {
	           var lock = true;
	           for (var prop in json) {
	               if (prop == 'opacity') {
	                   current = parseFloat(window.getComputedStyle(obj, null)[prop]) * 100;
	               } else {
	                   current = parseInt(window.getComputedStyle(obj, null)[prop]);
	               }
	               speed = (json[prop] - current) / 7;
	               speed = speed > 0 ? Math.ceil(speed) : Math.floor(speed);
	   
	               if (prop == 'opacity') {
	                   obj.style[prop] = (current + speed) / 100;
	               } else {
	                   obj.style[prop] = current + speed + 'px';
	               }
	               if (current != json[prop]) {
	                   lock = false;
	               }
	           }
	           if (lock) {
	               clearInterval(obj.timer);
	               typeof callback == 'function' ? callback() : '';
	           }
	       }, 30)
};
// 弹性运动
$.ElasticMovement= (obj, target)=> {
	      clearInterval(obj.timer);
	         var iSpeed = 40,
	             a, u = 0.8;
	         obj.timer = setInterval(function () {
	             a = (target - obj.offsetLeft) / 8;
	             iSpeed = iSpeed + a;
	             iSpeed = iSpeed * u;
	             if (Math.abs(iSpeed) <= 1 && Math.abs(a) <= 1) {
	                 console.log('over')
	                 clearInterval(obj.timer);
	                 obj.style.left = target + 'px';
	             } else {
	                 obj.style.left = obj.offsetLeft + iSpeed + 'px';
	             }
	         }, 30);
};
// 自己的foreach方法
$.foreach= (func, obj)=> {
	         var len = this.length;
	         var _this = arguments[1] ? arguments[1] : window;
	         // var _this=arguments[1]||window;
	         for (var i = 0; i < len; i++) {
	             func.call(_this, this[i], i, this)
	         }
};
// 封装自己的filter方法
$.filter= (func, obj)=> {
					 var len = this.length;
					 var arr = [];
					 var _this = arguments[1] || window;
					 for (var i = 0; i < len; i++) {
							 func.call(_this, this[i], i, this) && arr.push(this[i]);
					 }
					 return arr;
};
// 封装自己的数组map方法
$.map= (func)=> {
	         var arr = [];
	         var len = this.length;
	         var _this = arguments[1] || window;
	         for (var i = 0; i < len; i++) {
	             arr.push(func.call(_this, this[i], i, this));
	         }
	         return arr;
};
// 封装自己的数组every方法
$.every= (func)=> {
							var flag = true;
	            var len = this.length;
	            var _this = arguments[1] || window;
	            for (var i = 0; i < len; i++) {
	                if (func.apply(_this, [this[i], i, this]) == false) {
	                    flag = false;
	                    break;
	                }
	            }
	            return flag;
};
// 数组reduce方法
$.reduce= (func, initialValue)=> {
							var len = this.length,
							        nextValue,
							        i;
							    if (!initialValue) {
							        // 没有传第二个参数
							        nextValue = this[0];
							        i = 1;
							    } else {
							        // 传了第二个参数
							        nextValue = initialValue;
							        i = 0;
							    }
							    for (; i < len; i++) {
							        nextValue = func(nextValue, this[i], i, this);
							    }
							    return nextValue;
};
// 获取url中的参数
$.getWindonHref= ()=> {
								var sHref = window.location.href;
						    var args = sHref.split('?');
						    if (args[0] === sHref) {
						        return '';
						    }
						    var hrefarr = args[1].split('#')[0].split('&');
						    var obj = {};
						    for (var i = 0; i < hrefarr.length; i++) {
						        hrefarr[i] = hrefarr[i].split('=');
						        obj[hrefarr[i][0]] = hrefarr[i][1];
						    }
						    return obj;
};
// 数组排序
$.quickArr= (arr)=> {
							  if (arr.length <= 1) {
							        return arr;
							    }
							    var left = [],
							        right = [];
							    var pIndex = Math.floor(arr.length / 2);
							    var p = arr.splice(pIndex, 1)[0];
							    for (var i = 0; i < arr.length; i++) {
							        if (arr[i] <= p) {
							            left.push(arr[i]);
							        } else {
							            right.push(arr[i]);
							        }
							    }
							    // 递归
							    return quickArr(left).concat([p], quickArr(right));
};
// 冒泡排序
$.bubbleSort= (arr)=> {
	         for (var i = 0; i < arr.length - 1; i++) {
	                 for (var j = i + 1; j < arr.length; j++) {
	                     if (arr[i] > arr[j]) {
	                         var temp = arr[i];
	                         arr[i] = arr[j];
	                         arr[j] = temp;
	                     }
	                 }
	             }
	             return arr;
};
// 遍历dom树
$.traverse= (element, callback)=> {
	         callback(element);
	            var list = element.children;
	            for (var i = 0; i < list.length; i++) {
	                traverse(list[i], callback);
	            }
};
// 原生js封装ajax
$.ajax= (method, url, callback, data, flag)=> {
	          var xhr;
	            flag = flag || true;
	            method = method.toUpperCase();
	            if (window.XMLHttpRequest) {
	                xhr = new XMLHttpRequest();
	            } else {
	                xhr = new ActiveXObject('Microsoft.XMLHttp');
	            }
	            xhr.onreadystatechange =  ()=> {
	                if (xhr.readyState == 4 && xhr.status == 200) {
	                    console.log(2)
	                    callback(xhr.responseText);
	                }
	            }
	        
	            if (method == 'GET') {
	                var date = new Date(),
	                timer = date.getTime();
	                xhr.open('GET', url + '?' + data + '&timer' + timer, flag);
	                xhr.send()
	                } else if (method == 'POST') {
	                xhr.open('POST', url, flag);
	                xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
	                xhr.send(data);
	            }
};
// 异步加载script
$.loadScript= (url, callback)=> {
	            var oscript = document.createElement('script');
	             if (oscript.readyState) { // ie8及以下版本
	                 oscript.onreadystatechange =  ()=> {
	                     if (oscript.readyState === 'complete' || oscript.readyState === 'loaded') {
	                         callback();
	                     }
	                 }
	             } else {
	                 oscript.onload =  ()=> {
	                     callback()
	                 };
	             }
	             oscript.src = url;
	             document.body.appendChild(oscript);
};
// cookie管理
$.cookie ={
    set: (name, value, time)=> {
        document.cookie = name + '=' + value + '; max-age=' + time;
        return this;
    },
    remove:(name)=> {
        return this.setCookie(name, '', -1);
    },
    get: (name, callback)=> {
        var allCookieArr = document.cookie.split('; ');
        for (var i = 0; i < allCookieArr.length; i++) {
            var itemCookieArr = allCookieArr[i].split('=');
            if (itemCookieArr[0] === name) {
                return itemCookieArr[1]
            }
        }
        return undefined;
    }
}

// 实现bind方法
$.bind= (target)=> {
	        var target = target || window;
	           var _args1 = [].slice.call(arguments, 1);
	           var self = this;
	           var temp = function () {};
	           var F = function () {
	               var _args2 = [].slice.call(arguments, 0);
	               var parasArr = _args1.concat(_args2);
	               return self.apply(this instanceof temp ? this : target, parasArr)
	           }
	           temp.prototype = self.prototype;
	           F.prototype = new temp();
	           return F;
};

// 实现call方法
$.call= ()=> {
	  var ctx = arguments[0] || window;
	    ctx.fn = this;
	    var args = [];
	    for (var i = 1; i < arguments.length; i++) {
	        args.push(arguments[i])
	    }
	    var result = ctx.fn(...args);
	    delete ctx.fn;
	    return result;
};

// 实现apply方法
$.apply= (target)=> {
	 var ctx = arguments[0] || window;
	    ctx.fn = this;
	    if (!arguments[1]) {
	        var result = ctx.fn();
	        delete ctx.fn;
	        return result;
	    }
	    var result = ctx.fn(...arguments[1]);
	    delete ctx.fn;
	    return result;
};

// 防抖
$.debounce= (handle, delay)=> {
	  var timer = null;
	     return function () {
	         var _self = this,
	             _args = arguments;
	         clearTimeout(timer);
	         timer = setTimeout(function () {
	             handle.apply(_self, _args)
	         }, delay)
	     }
};

// 节流
$.throttle= (handler, wait)=> {
		var lastTime = 0;
			return function (e) {
					var nowTime = new Date().getTime();
					if (nowTime - lastTime > wait) {
							handler.apply(this, arguments);
							lastTime = nowTime;
					}
			}
};

// requestAnimFrame兼容性方法
$.requestAnimFrame= (handler, wait)=> {
		 return window.requestAnimationFrame ||
		        window.webkitRequestAnimationFrame ||
		        window.mozRequestAnimationFrame ||
		        function (callback) {
		            window.setTimeout(callback, 1000 / 60);
		        };
};

// jsonp底层方法
$.jsonp= (url, callback)=> {
		  var oscript = document.createElement('script');
		     if (oscript.readyState) { // ie8及以下版本
		         oscript.onreadystatechange = function () {
		             if (oscript.readyState === 'complete' || oscript.readyState === 'loaded') {
		                 callback();
		             }
		         }
		     } else {
		         oscript.onload = function () {
		             callback()
		         };
		     }
		     oscript.src = url;
		     document.body.appendChild(oscript);
};

// 获取url上的参数
$.getUrlParam= (sUrl, sKey)=> {
		   var result = {};
		     sUrl.replace(/(\w+)=(\w+)(?=[&|#])/g, function (ele, key, val) {
		         if (!result[key]) {
		             result[key] = val;
		         } else {
		             var temp = result[key];
		             result[key] = [].concat(temp, val);
		         }
		     })
		     if (!sKey) {
		         return result;
		     } else {
		         return result[sKey] || '';
		     }
};

// 格式化时间
$.formatDate= (t, str)=> {
		  var obj = {
		         yyyy: t.getFullYear(),
		         yy: ("" + t.getFullYear()).slice(-2),
		         M: t.getMonth() + 1,
		         MM: ("0" + (t.getMonth() + 1)).slice(-2),
		         d: t.getDate(),
		         dd: ("0" + t.getDate()).slice(-2),
		         H: t.getHours(),
		         HH: ("0" + t.getHours()).slice(-2),
		         h: t.getHours() % 12,
		         hh: ("0" + t.getHours() % 12).slice(-2),
		         m: t.getMinutes(),
		         mm: ("0" + t.getMinutes()).slice(-2),
		         s: t.getSeconds(),
		         ss: ("0" + t.getSeconds()).slice(-2),
		         w: ['日', '一', '二', '三', '四', '五', '六'][t.getDay()]
		     };
		     return str.replace(/([a-z]+)/ig, function ($1) {
		         return obj[$1]
		     });
};

// 验证邮箱的正则表达式
$.isAvailableEmail= (sEmail)=> {
		  var reg = /^([\w+\.])+@\w+([.]\w+)+$/
		    return reg.test(sEmail)
};

// 函数柯里化
$.curryIt= (fn)=> {
		  var length = fn.length,
		         args = [];
		     var result = function (arg) {
		         args.push(arg);
		         length--;
		         if (length <= 0) {
		             return fn.apply(this, args);
		         } else {
		             return result;
		         }
		     }
		     return result;
};

// 大数相加
$.sumBigNumber= (a, b)=> {
		    var res = '', //结果
		          temp = 0; //按位加的结果及进位
		      a = a.split('');
		      b = b.split('');
		      while (a.length || b.length || temp) {
		          //~~按位非 1.类型转换，转换成数字 2.~~undefined==0 
		          temp += ~~a.pop() + ~~b.pop();
		          res = (temp % 10) + res;
		          temp = temp > 9;
		      }
		      return res.replace(/^0+/, '');
};

// 单例模式
$.getSingle= (func)=> {
		      var result;
		        return function () {
		            if (!result) {
		                result = new func(arguments);
		            }
		            return result;
		        }
};

// 获取localStorage的已使用空间
$.getLSUsedSpace= ()=> {
		        return Object.keys(localStorage).reduce((total, curKey) => {
		              if (!localStorage.hasOwnProperty(curKey)) {
		                  return total;
		              }
		              total += localStorage[curKey].length + curKey.length;
		              return total;
		          }, 0)
							// 使用实例:
							// localStorage.clear();
							// localStorage.a = "啊";
							// console.log(getLSUsedSpace()); // 2
};

// 实现带图带事件的桌面通知
$.doNotify= (title, options = {}, events = {})=> {
		        const notification = new Notification(title, options);
		            for (let event in events) {
		                notification[event] = events[event];
		            }
};

// 实现带图带事件的桌面通知
$.notify= (title, options = {}, events = {})=> {
		         if (!("Notification" in window)) {
		                return console.error("This browser does not support desktop notification");
		            }
		            else if (Notification.permission === "granted") {
		                doNotify(title, options, events);
		            } else if (Notification.permission !== "denied") {
		                Notification.requestPermission().then(function (permission) {           
		                    if (permission === "granted") {
		                        doNotify(title, options, events);
		                    }
		                });
		            }
								
								// 实例:
								// this.$.notify("中奖提示", {
								//             icon: "https://sf1-ttcdn-tos.pstatp.com/img/user-avatar/f1a9f122e925aeef5e4534ff7f706729~300x300.image",
								//             body: "恭喜你，掘金签到一等奖",
								//             tag: "prize"
								//         }, {
								//             onclick(ev) {
								//                 console.log(ev);
								//                 ev.target.close();
								//                 window.focus();
								//             }
								//         })
};

// 相对地址转为绝对地址
$.realativeToAbs= (href)=> {
		        let aEl = document.createElement("a");
						aEl.href = href;    
						const result = aEl.href;
						aEl = null;
						return result;
};

// 基于URL或者Crypto.getRandomValues生成UUID
$.genUUID= (href)=> {
		        const url = URL.createObjectURL(new Blob([]));
						// const uuid = url.split("/").pop();
						const uuid = url.substring(url.lastIndexOf('/')+ 1);
						URL.revokeObjectURL(url);
						return uuid;
};


// 基于toLocaleString千分位(千万亿以下的数适用)
$.formatMoney= (num)=> {
		        return (+num).toLocaleString("en-US");
						// 实例:
						// console.log(this.$.formatMoney(123456789));  // 123,456,789
};

// Promise顺序执行
$.runPromises= (promiseCreators, initData)=> {
		        return promiseCreators
		                .reduce((promise, next) => promise
		                        .then((data) => next(data))
		                    , Promise.resolve(initData));
						// 实例:
						// var promise1 = function (data = 0) {
						//     return new Promise(resolve => {
						//         resolve(data + 1000);
						//     });
						// }
						// var promise2 = function (data) {
						//     return new Promise(resolve => {
						//         resolve(data -500);
						//     });
						// }
						// this.$.runPromises([promise1, promise2], 1).then(res=>console.log(res));
};

// 延迟执行某函数,只会执行一次
$.delay= (fn = () => { }, delay = 5000, context = null)=> {
		         let ticket = null;
		            let runned = false;
		            return {
		                run(...args) {
		                    return new Promise((resolve, reject) => {
		                        if (runned === true) {
		                            return;
		                        }
		                        runned = true;
		                        ticket = setTimeout(async () => {
		                            try {
		                                const res = await fn.apply(context, args);
		                                resolve(res);
		                            } catch (err) {
		                                reject(err)
		                            }
		                        }, delay)
		                    })
		                },
		                cancel: () => {
		                    clearTimeout(ticket);
		                }
		            }
								// 实例:
								// delay(function () {
								//     console.log("你们好");
								// }).run();
								
								// const { run, cancel } = this.$.delay(function (name) {
								//     console.log("你好：", name);
								// });
								// run("吉他");
								// run("吉他");
};

// 滑滚动页面到顶部
$.scrollToTop= ()=> {
		        let scrollTop = document.documentElement.scrollTop || document.body.scrollTop;
		           if (scrollTop > 0) {
		               window.requestAnimationFrame(scrollToTop);
		               window.scrollTo(0, scrollTop - scrollTop / 8);
		           }
};

// 禁止选择和复制
// css方案,js方案暂不考虑
// body {
//     -moz-user-select: none;
//     -webkit-user-select: none;
//     -ms-user-select: none;
//     -khtml-user-select: none;
//     user-select: none;
// }
// 到目前为止59个函数,1个解决方案
export default $;
